package com.lightkits.wms.domain.retirelib.impl;

import com.lightkits.common.TransactionValidate;
import com.lightkits.common.db.entity.FndExceptionBase;
import com.lightkits.common.db.entity.FndItemBase;
import com.lightkits.common.db.entity.FndOrganizationBase;
import com.lightkits.common.db.entity.FndUomBase;
import com.lightkits.common.db.entity.FndWarehouse;
import com.lightkits.common.db.entity.FndWmArea;
import com.lightkits.common.db.entity.FndWmMoveTypeBase;
import com.lightkits.common.db.entity.FndWorker;
import com.lightkits.common.db.entity.WmExecuteLine;
import com.lightkits.common.db.entity.WmRequestHeader;
import com.lightkits.common.db.entity.WmRequestLine;
import com.lightkits.common.db.entity.event.BdEvent;
import com.lightkits.common.db.entity.event.BdEventRecord;
import com.lightkits.common.service.CommonTransactionService;
import com.lightkits.framework.common.exception.LightKitsBizException;
import com.lightkits.framework.common.logging.Logger;
import com.lightkits.framework.common.logging.LoggerFactory;
import com.lightkits.framework.common.model.CheckResult;
import com.lightkits.framework.common.model.IResult;
import com.lightkits.framework.common.utility.json.JsonUtil;
import com.lightkits.framework.common.utility.object.ObjectUtil;
import com.lightkits.framework.common.utility.validate.IntegrityValidator;
import com.lightkits.wms.domain.nontaskpickinglist.repo.WmRequestHeaderService;
import com.lightkits.wms.domain.nontaskpickinglist.repo.WmRequestLineService;
import com.lightkits.wms.domain.rawmatstorage.repo.WmExecuteLineService;
import com.lightkits.wms.domain.retireLib.CreateRetireEventParams;
import com.lightkits.wms.domain.retirelib.CreateRetireDocParams;
import com.lightkits.wms.domain.retirelib.UseRetireParams;
import com.lightkits.wms.domain.saveonhand.repo.BdEventRecordService;
import com.lightkits.wms.domain.saveonhand.repo.BdEventService;
import com.lightkits.wms.domain.stocktransfer.service.MiscellAdjustDomain;
import com.lightkits.wms.dto.retirelib.model.RetireLibDto;
import com.lightkits.wms.dto.stocktransfer.model.MiscellAdjust;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 在库报废
 *
 * @author jing.wei@hand-china.com
 * @date 2019/6/10 15:58
 **/
@Service
public class UseRetireParamsImpl implements UseRetireParams {
    private static final Logger LOGGER = LoggerFactory.getLogger(UseRetireParamsImpl.class);

    private final CreateRetireDocParams createRetireDocParams;
    private final CreateRetireEventParams createRetireEventParams;
    private final WmRequestLineService wmRequestLineService;
    private final WmRequestHeaderService wmRequestHeaderService;
    private final WmExecuteLineService wmExecuteLineService;
    private final BdEventService bdEventService;
    private final BdEventRecordService bdEventRecordService;
    private final CommonTransactionService commonTransactionService;
    @Autowired
    private MiscellAdjustDomain miscellAdjustDomain;

    @Autowired
    public UseRetireParamsImpl(CreateRetireDocParams createRetireDocParams, CreateRetireEventParams createRetireEventParams, WmRequestLineService wmRequestLineService, WmRequestHeaderService wmRequestHeaderService, WmExecuteLineService wmExecuteLineService, BdEventService bdEventService, BdEventRecordService bdEventRecordService, CommonTransactionService commonTransactionService) {
        this.createRetireDocParams = createRetireDocParams;
        this.createRetireEventParams = createRetireEventParams;
        this.wmRequestLineService = wmRequestLineService;
        this.wmRequestHeaderService = wmRequestHeaderService;
        this.wmExecuteLineService = wmExecuteLineService;
        this.bdEventService = bdEventService;
        this.bdEventRecordService = bdEventRecordService;
        this.commonTransactionService = commonTransactionService;
    }

    /**
     * 在库报废参数校验
     *
     * @param workerId      操作员Id
     * @param orgId         组织Id
     * @param retireLibDtos 报废列表参数
     * @return
     */
    private IResult checkParams(String workerId, String orgId, String moveTypeId, List<RetireLibDto> retireLibDtos) {
        try {
            if (ObjectUtil.isNullOrEmpty(retireLibDtos)) {
                return IResult.fail("the Params is invalid");
            }
            IntegrityValidator.begin().validate(workerId, "Worker Id")
                    .validate(moveTypeId, "Move Type Id")
                    .validate(orgId, "Organization Id");
            TransactionValidate checkHead = TransactionValidate
                    .beginValidity(FndOrganizationBase.class);
            checkHead.checkIdValidity(
                    ObjectUtil.toString(orgId),
                    "ORGANIZATION_ID");

            checkHead = TransactionValidate
                    .beginValidity(FndWorker.class);
            checkHead.checkIdValidity(
                    ObjectUtil.toString(workerId),
                    "ID");
            checkHead = TransactionValidate
                    .beginValidity(FndWmMoveTypeBase.class);
            checkHead.checkIdValidity(
                    ObjectUtil.toString(moveTypeId),
                    "ID");

            retireLibDtos.forEach(dto -> {
                //必输校验
                IntegrityValidator.begin()
                        .validate(dto.getScrapItemId(), "Scrap Item Id")
                        .validate(dto.getUomCode(), "Uom Code")
                        .validate(dto.getWarehouseId(), "Warehouse Id")
                        .validate(dto.getPendingWarehouseId(), "Pending Warehouse Id");
                //有效性校验
                TransactionValidate check = TransactionValidate
                        .beginValidity(FndItemBase.class);
                check.checkIdValidity(
                        ObjectUtil.toString(dto.getScrapItemId()),
                        "ITEM_ID");

                check = TransactionValidate
                        .beginValidity(FndWarehouse.class);
                check.checkIdValidity(
                        ObjectUtil.toString(dto.getWarehouseId()),
                        "ID");

                check = TransactionValidate
                        .beginValidity(FndWmArea.class);
                check.checkIdValidity(
                        ObjectUtil.toString(dto.getWmAreaId()),
                        "ID");

                check = TransactionValidate
                        .beginValidity(FndWarehouse.class);
                check.checkIdValidity(
                        ObjectUtil.toString(dto.getPendingWarehouseId()),
                        "ID");

                check = TransactionValidate
                        .beginValidity(FndWmArea.class);
                check.checkIdValidity(
                        ObjectUtil.toString(dto.getPendingWmAreaId()),
                        "ID");

                check = TransactionValidate
                        .beginValidity(FndUomBase.class);
                check.checkIdValidity(
                        ObjectUtil.toString(dto.getUomCode()),
                        "UOM_CODE");

                check = TransactionValidate
                        .beginValidity(FndExceptionBase.class);
                check.checkIdValidity(
                        ObjectUtil.toString(dto.getNgReasonId()),
                        "ID");

                //数字参数有效性校验
                Pattern pattern = Pattern.compile("([1-9]\\d*\\.?\\d*)|(0\\.\\d*[1-9])");
                if (!pattern.matcher(dto.getQty()).matches()) {
                    throw new LightKitsBizException("The Goods Total is invalid");
                }
            });
        } catch (LightKitsBizException e) {
            return e.result();
        }
        return IResult.success();
    }

    /**
     * 在库报废
     *
     * @param workerId      员工Id
     * @param orgId         组织Id
     * @param retireLibDtos 在库报废列表参数
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CheckResult<String> retireLib(String workerId, String orgId, String moveTypeId, List<RetireLibDto> retireLibDtos) {
        CheckResult checkRes = new CheckResult();
        checkRes.setSuccessful(true);
        try {
            //校验报废参数
            IResult result = this.checkParams(workerId, orgId, moveTypeId, retireLibDtos);
            if (!result.isSuccessful()) {
                return result.fill(checkRes);
            }
            //创建领料单头
            CheckResult checkResult = createRetireDocParams.createRequestHeader(workerId, orgId);
            if (!checkResult.isSuccessful() || checkResult.getData() == null) {
                throw new LightKitsBizException(checkResult.getMessage());
            }
            WmRequestHeader requestHeader = (WmRequestHeader) checkResult.getData();
            boolean insertHeadFlag = wmRequestHeaderService.insert(requestHeader);
            if (!insertHeadFlag) {
                throw new LightKitsBizException("Insert Request Header Failed");
            }
            //创建领料单头事件
            checkResult = createRetireEventParams.createEvent(workerId, orgId);
            if (!checkResult.isSuccessful() || checkResult.getData() == null) {
                throw new LightKitsBizException(checkResult.getMessage());
            }
            BdEvent bdEvent = (BdEvent) checkResult.getData();
            boolean insertHeadEventFlag = bdEventService.insert(bdEvent);
            if (!insertHeadEventFlag) {
                throw new LightKitsBizException("Insert Request Header Event Failed");
            }
            List<BdEventRecord> eventRecords = new ArrayList<>();
            //创建领料单头快照
            checkResult = createRetireEventParams.createEventRecord("WM_REQUEST_HEADER",
                    "SCRAP", requestHeader.getId(),
                    "HEADER", JsonUtil.toString(requestHeader));
            if (!checkResult.isSuccessful() || checkResult.getData() == null) {
                throw new LightKitsBizException(checkResult.getMessage());
            }
            BdEventRecord eventRecord = (BdEventRecord) checkResult.getData();
            eventRecord.setEventId(bdEvent.getId());
            eventRecords.add(eventRecord);
            //创建领料单行
            checkResult = createRetireDocParams.createRequestLines(retireLibDtos
                    , requestHeader.getId(), moveTypeId);
            if (!checkResult.isSuccessful() || checkResult.getData() == null) {
                throw new LightKitsBizException(checkResult.getMessage());
            }
            List<WmRequestLine> requestLines = (List<WmRequestLine>) checkResult.getData();
            boolean insertRequestLineFlag = wmRequestLineService.insertBatch(requestLines);
            if (!insertRequestLineFlag) {
                throw new LightKitsBizException("Insert Request Lines Failed");
            }
            //创建领料单行快照
            requestLines.forEach(line -> {
                CheckResult<BdEventRecord> record = createRetireEventParams.createEventRecord("WM_REQUEST_LINE",
                        "SCRAP", line.getId(),
                        "LINE", JsonUtil.toString(line));
                if (!record.isSuccessful() || record.getData() == null) {
                    throw new LightKitsBizException(record.getMessage());
                }
                record.getData().setEventId(bdEvent.getId());
                eventRecords.add(record.getData());

            });
            //创建领料单执行
            checkResult = createRetireDocParams.createExecuteLine(requestLines
                    , requestHeader.getId(), bdEvent.getId());
            if (!checkResult.isSuccessful() || checkResult.getData() == null) {
                throw new LightKitsBizException(checkResult.getMessage());
            }
            List<WmExecuteLine> executeLines = (List<WmExecuteLine>) checkResult.getData();
            boolean inserExeFlag = wmExecuteLineService.insertBatch(executeLines);
            if (!inserExeFlag) {
                throw new LightKitsBizException("Insert Execute Lines Failed");
            }
            //创建领料单执行表快照
            executeLines.forEach(line -> {
                CheckResult<BdEventRecord> record = createRetireEventParams.createEventRecord("WM_EXECUTE_LINE",
                        "SCRAP", line.getId(),
                        "EXELINE", JsonUtil.toString(line));
                if (!record.isSuccessful() || record.getData() == null) {
                    throw new LightKitsBizException(record.getMessage());
                }
                record.getData().setEventId(bdEvent.getId());
                eventRecords.add(record.getData());

            });
            //插入快照
            boolean insertRecordsFlag = bdEventRecordService.insertBatch(eventRecords);
            if (!insertRecordsFlag) {
                throw new LightKitsBizException("Insert Event Records Failed");
            }
            //现有量变更
            checkResult = createRetireDocParams.createOnhand(requestLines, requestHeader, moveTypeId, bdEvent.getId());
            if (!checkResult.isSuccessful() || checkResult.getData() == null) {
                throw new LightKitsBizException(checkResult.getMessage());
            }
            List<MiscellAdjust> dtoList = (List<MiscellAdjust>) checkResult.getData();
            dtoList.forEach(dto -> {
                IResult result1 = miscellAdjustDomain.misCellAdjust(dto);
                if (!result1.isSuccessful()) {
                    throw new LightKitsBizException(result1.getMessage());
                }
            });
            checkRes.setData(requestHeader.getId().toString());
        } catch (LightKitsBizException e) {
            e.printStackTrace();
            e.fill(checkRes);
        } catch (Exception e) {
            checkRes.setSuccessful(false);
            checkRes.setMessage("Retire Libary error");
            return checkRes;
        }
        return checkRes;
    }

}
